package io.gitee.shengzheng1999.esbcommon.common.utils;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URLEncoder;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.web.multipart.MultipartFile;

import io.gitee.shengzheng1999.esbcommon.common.utils.LogUtil;
import io.gitee.shengzheng1999.esbcommon.exception.BaseException;
import io.gitee.shengzheng1999.esbcommon.exception.ExceptionCodes;

/**
 * @className		: FileUtil
 * @description	: 文件工具类
 * @summary		:
 * @history		:
 * ------------------------------------------------------------------------------
 * date			version		modifier		remarks                   
 * ------------------------------------------------------------------------------
 * 2023/05/28	1.0.0		sheng.zheng		初版
 *
 */
public class FileUtil {
	private static final String charset = "utf-8";
	
	//========================= 文件操作 ===========================================    
    /**
     * 
     * @methodName		: is2ByeteArray
     * @description	: 从inputStream读取数据到byte[]
     * @param is		: 输入的inputStream对象
     * @return			: byte数组
     * @throws IOException: 读取失败，抛出异常
     * @history		:
     * ------------------------------------------------------------------------------
     * date			version		modifier		remarks                   
     * ------------------------------------------------------------------------------
     * 2021/01/01	1.0.0		sheng.zheng		初版
     *
     */
	public static byte[] is2ByeteArray(InputStream is) throws IOException {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		byte[] buff = new byte[1024];
		int rc = 0;
		while((rc=is.read(buff, 0, 1024))>0) {
			// 每次读取1K字节
			baos.write(buff, 0, rc);
		}
		baos.close();
		
		return baos.toByteArray();
	}  
	
	/**
	 * 
	 * @methodName		: readTxt
	 * @description	: 读取文本文件到字符串
	 * @param file		: 文件文件
	 * @return			: 文本文件的内容
	 * @throws IOException: 读取失败，抛出异常
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	public static String readTxt(File file) throws IOException {
	    String s = "";
	    InputStreamReader in = new InputStreamReader(new FileInputStream(file),charset);
	    BufferedReader br = new BufferedReader(in);
	    StringBuffer content = new StringBuffer();
	    while ((s=br.readLine())!=null){
	      content = content.append(s);
	    }
	    br.close();
	    
	    return content.toString();
	}
	
	/**
	 * 
	 * @methodName		: writeTxt
	 * @description	: 将文本内容保持到文件文件中
	 * @param filePath	: 文件路径
	 * @param content	: 文件内容
	 * @throws IOException: 操作失败，抛出异常
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	public static void writeTxt(String filePath,String content) throws IOException{
		FileOutputStream fos = new FileOutputStream(filePath);
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos, "UTF-8"));
        bw.write(content);
        bw.close();		
	}
	
	/**
	 * 
	 * @methodName		: copyFile
	 * @description	: 复制文件
	 * @param src		: 源文件路径
	 * @param dest		: 目标文件路径
	 * @return			: 复制成功返回true，否则为false。
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	public static boolean copyFile(String src, String dest) {
		String inputname = src;
		String outputname = dest;
		
		try{
			FileInputStream input  = new FileInputStream(inputname);
			FileOutputStream output = new FileOutputStream(outputname);
		
			int in  = input.read();
		
			while(in!=-1){
				output.write(in);
				in = input.read();
			}
			input.close();
			output.close();
		}catch(IOException e){
			LogUtil.error(e);
			return false;
		}
		
		return true;		
	}	
	
	/**
	 * 
	 * @methodName		: moveFile
	 * @description	: 移动文件
	 * @param src		: 源文件路径
	 * @param dest		: 目标文件路径
	 * @return			: 成功返回true，否则为false
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2022/06/27	1.0.0		sheng.zheng		初版
	 *
	 */
	public static void moveFile(String src, String dest) {
		// 检查源文件
		if(checkFileExist(src) == false) {
			throw new BaseException(ExceptionCodes.READFILE_FAILED,"source file not exist:" + src);
		}
		
		if(checkFileExist(dest)) {
			// 如果目标路径已存在
			// 删除目标文件
			try {
				deleteFile(dest);				
			}catch(Exception e) {
				LogUtil.error(e);
				throw new BaseException(ExceptionCodes.DELETEFILE_FAILED,"failed to delete exist file:"+dest);				
			}
		}
		
		// 复制文件
		boolean bRet = copyFile(src,dest);
		if (bRet == false) {
			throw new BaseException(ExceptionCodes.COPYFILE_FAILED,"failed to copy file from src = " + src + " to dest = " + dest);							
		}
		
		// 删除源文件
		try {
			deleteFile(src);				
		}catch(Exception e) {
			LogUtil.error(e);
			throw new BaseException(ExceptionCodes.DELETEFILE_FAILED,"failed to delete src file:" + src);				
		}
	}
	
	/**
	 * 
	 * @methodName		: renameFile
	 * @description	: 重命名文件
	 * @param src		: 源文件路径
	 * @param newName	: 新的文件名
	 * @param bForce	: 如果新的文件名的文件已存在，是否删除,true表示删除
	 * @return			: 成功返回true，否则为false
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2022/06/28	1.0.0		sheng.zheng		初版
	 *
	 */
	public static boolean renameFile(String src,String newName,boolean bForce) {
		boolean bRet = false;
		File file = new File(src);
		if (!file.exists()) {
			// 文件不存在
			return bRet;
		}
		// 获取原文件名
		int dirPos = src.lastIndexOf("/");
		if (dirPos == -1) {
			// 不包含目录路径
			return bRet;
		}
		String dir = src.substring(0,dirPos+1);
		String newPath = dir + newName;
		File destFile = new File(newPath);
		if (destFile.exists() && bForce) {
			// 如果目标文件存在，且强制删除
			destFile.delete();
		}
		
		// 重命名
		bRet = file.renameTo(destFile);
		
		return bRet;
	}
	
	/**
	 * 
	 * @methodName		: getFilenameWithoutSuffix
	 * @description	: 取得不含后缀的文件名
	 * @param filePath	: 文件路径
	 * @return			: 不含后缀的文件名
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	public static String getFilenameWithoutSuffix(String filePath) {
		// 去掉目录
		String fullFilename = filePath.substring(filePath.lastIndexOf("/")+1);
		// 获取文件名
		String filename = fullFilename.substring(0,fullFilename.lastIndexOf("."));	
		return filename;
	}
	
	/**
	 * 
	 * @methodName		: checkFileExist
	 * @description	: 检查文件是否存在
	 * @param filePath	: 文件路径
	 * @return			: 文件存在返回true，否则为false。
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	public static boolean checkFileExist(String filePath) {
		boolean bRet = false;
		File file = new File(filePath);
		if (file.exists()) {
			// 文件存在
			bRet = true;
		}	
		return bRet;
	}
	
	/**
	 * 
	 * @methodName		: deleteFile
	 * @description	: 删除文件
	 * @param filePath	: 文件路径
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	public static void deleteFile(String filePath) {
		File file = new File(filePath);
		if (file.exists()) {
			// 文件存在
			file.delete();
		}			
	}	
	
	/**
	 * 
	 * @methodName		: deleteFolder
	 * @description	: 删除目录夹
	 * @param file		: File对象
	 * @return		: 成功返回true，否则为false
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/29	1.0.0		sheng.zheng		初版
	 *
	 */
    public static boolean deleteFolder(File file){
        // 当传入的是文件时，直接删除
        if(file.isFile()) {
            return file.delete();
        	
        }
 
        // 当传入的是文件夹时
        File[] files = file.listFiles();
        // 空文件夹，直接删除
        if(files == null || files.length == 0) {        	
            return file.delete();
        }
        // 非空文件夹，遍历删除
        for(File f : files){
            if(f.isFile()) {
            	// 文件直接删除
                f.delete();            	
            }
            else if (f.isDirectory()) {
            	// 文件夹递归删除            	
                deleteFolder(f);
            }
        }
 
        // 最后删除最外层空文件夹
        return file.delete();
    }
    
	/**
	 * 
	 * @methodName		: cleanDir
	 * @description	: 清空目录
	 * @param srcDir	: 指定目录
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/29	1.0.0		sheng.zheng		初版
	 *
	 */
    public static void cleanDir(String srcDir) {
		File srcFile = new File(srcDir);
		File[] files = srcFile.listFiles();
		for(File file : files) {
			if (file.isDirectory()) {
				deleteFolder(file);
			}else if(file.isFile()) {
				// 如果为文件，则删除
				file.delete();
			}
		}		
	}  
    
	/**
	 * 
	 * @methodName		: backupDir
	 * @description	: 备份路径
	 * @param srcDir	: 源目录
	 * @param destDir	: 目标目录
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/29	1.0.0		sheng.zheng		初版
	 *
	 */
    public static void backupDir(String srcDir,String destDir) {
		File srcFile = new File(srcDir);
		File[] files = srcFile.listFiles();
		for(File file : files) {
			String name = file.getName();
			String srcPath = srcDir + "/" + name;
			String destPath = destDir + "/" + name;
			if (file.isDirectory()) {
				// 如果为目录，则
				File dFile = new File(destPath);
				if (!dFile.exists()) {
					dFile.mkdirs();
				}
				// 递归调用
				backupDir(srcPath,destPath);
			}else if(file.isFile()) {
				// 如果为文件，则复制
				FileUtil.copyFile(srcPath, destPath);
			}
		}
	}    
    
    /**
     * 
     * @methodName		: makeDir
     * @description	: 创建目录
     * @param dir		: 目录路径名
     * @history		:
     * ------------------------------------------------------------------------------
     * date			version		modifier		remarks                   
     * ------------------------------------------------------------------------------
     * 2021/01/01	1.0.0		sheng.zheng		初版
     *
     */
    public static boolean makeDir(String dir) {
    	File file = new File(dir);
    	if (!file.exists()) {
    		return file.mkdirs();
    	}
    	return true;
    }
	
	/**
	 * 
	 * @methodName		: closeStream
	 * @description	: 关闭文件流
	 * @param in		: 可关闭的数据流对象
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	public static void closeStream(Closeable in) {
		try {
			if(in != null) {
				in.close();
			}
		}catch(IOException e) {
			LogUtil.error(e);
		}
	} 
	
	//========================= 文件下载 ======================================    
	/**
	 * 
	 * @methodName		: download
	 * @description	: 下载指定路径的文件
	 * @param response	: reponse对象
	 * @param filePath	: 需要下载的文件路径
	 * @param filename	: 下载文件的文件名
	 * @param contentType	: response header中的ContentType，常用取值如下：
	 * 		普通二进制文件	: application/octet-stream
	 * 		Excel文件		: application/vnd.ms-excel
	 * 		文本文件		: text/plain; charset=utf-8
	 * 		html文件		: text/html; charset=utf-8
	 * 		xml文件			: text/xml; charset=utf-8
	 * 		jpeg文件		: image/jpeg
	 * @throws Exception	: 异常发生时，抛出。没有异常，说明下载成功。
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	public static void download(HttpServletResponse response,String filePath,
			String filename,String contentType) throws Exception{
    	
    	File file = new File(filePath);
    	if (file.exists()) {
            //设置读取流的缓存为1K
            byte[] buffer = new byte[1024];
            FileInputStream fis = null;
            BufferedInputStream bis = null; 
            try {
                //设置ContentType
    			response.setContentType(contentType);
    			// 下载文件能正常显示中文
    			//String filename = filePath.substring(filePath.lastIndexOf("/")+1);
    			response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
    			// 获取输入流
    			fis = new FileInputStream(file);
    			bis = new BufferedInputStream(fis);
    			// 输出流
    			OutputStream os = response.getOutputStream();
    			int len = bis.read(buffer);
    			while (len != -1) {
    				os.write(buffer, 0, len);
    				len = bis.read(buffer);
    			}             	
            }catch(Exception e) {
            	throw e;            	
            }finally {
    			// 关闭流
    			closeStream(bis);
    			closeStream(fis);            	
            }			
    	} 
    }	
	
	/**
	 * 
	 * @methodName		: downloadStream
	 * @description	: 下载指定路径的文件
	 * @param response	: reponse对象
	 * @param is		: 需要下载的文件流
	 * @param filename	: 下载文件的文件名
	 * @param contentType	: response header中的ContentType，常用取值如下：
	 * 		普通二进制文件	: application/octet-stream
	 * 		Excel文件		: application/vnd.ms-excel
	 * 		文本文件		: text/plain; charset=utf-8
	 * 		html文件		: text/html; charset=utf-8
	 * 		xml文件			: text/xml; charset=utf-8
	 * 		jpeg文件		: image/jpeg
	 * @throws Exception	: 异常发生时，抛出。没有异常，说明下载成功。
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	public static void downloadStream(HttpServletResponse response,InputStream is,
			String filename,String contentType) throws Exception{
    	
        // 设置读取流的缓存为1K
        byte[] buffer = new byte[1024];
        BufferedInputStream bis = null; 
        try {
            // 设置ContentType
    		response.setContentType(contentType);
    		// 下载文件能正常显示中文
    		//String filename = filePath.substring(filePath.lastIndexOf("/")+1);
    		response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
    		// 获取输入流
    		bis = new BufferedInputStream(is);
    		// 输出流
    		OutputStream os = response.getOutputStream();
    		int len = bis.read(buffer);
    		while (len != -1) {
    			os.write(buffer, 0, len);
    			len = bis.read(buffer);
    		}         	
        }catch(Exception e) {
        	throw e;
        }finally {
    		// 关闭流
        	closeStream(bis);
        }
    }
	
	/**
	 * 
	 * @methodName		: upload
	 * @description	: 保存上传文件，并返回临时文件名
	 * @param upfile	: MultipartFile类型对象
	 * @return			: 临时文件名
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2022/03/01	1.0.0		sheng.zheng		初版
	 *
	 */
	public static String upload(MultipartFile upfile,String uploadDir) {
    	//获取上传的文件名
    	String fileName = upfile.getOriginalFilename(); 
    	//后缀名
        String suffixName = fileName.substring(fileName.lastIndexOf("."));
        //新文件名，随机6个字符，避免重复
        String randomStr = RandomStringUtils.randomAlphanumeric(6);
        long current = System.currentTimeMillis();
        String randomFilename = randomStr + "_" + current;
    	//临时文件名
    	String tmpFilename = randomFilename + suffixName; 
    	//临时目录路径
        String filePath = uploadDir + "/" + tmpFilename;
        File dest = new File(filePath);
        try {
        	//上传文件
        	upfile.transferTo(dest);
        } catch (Exception e) {
            LogUtil.error(e);
            throw new BaseException(ExceptionCodes.UPLOAD_READFILE_FAILED);
        }
        
		return tmpFilename;
	}		
}
